﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime;
namespace MatrixCalculator
{
    public class Calculator
    {
        private double[,] Z;
        private double[,] tmpMatrix;
        /// <summary>
        /// Součet dvou matic
        /// </summary>
        /// <param name="A">matice typu double</param>
        /// <param name="B">matice typu double</param>
        /// <returns>vrací součtovou matici typu double</returns>
        public double[,] add(double[,] A, double[,] B)
        {
            if (A.GetLength(0) != B.GetLength(0) || B.GetLength(1) != A.GetLength(1))
                throw new SquareException("Matice nejsou stejného řádu !! ");
            tmpMatrix = new double[A.GetLength(0), A.GetLength(1)];
            for (int i = 0; i < A.GetLength(0); i++)
            {
                for (int j = 0; j < A.GetLength(1); j++)
                {
                    tmpMatrix[i, j] = A[i, j] + B[i, j];
                }
            }
            return tmpMatrix;
        }

        public double[,] normScores(double[,] A, double[,] B)
        {
            double[,] tmp = new double[A.GetLength(1), B.GetLength(1)];
            for (int i = 0; i < tmp.GetLength(0); i++)
            {
                tmp[i, i] = 0.5;
            }
            return mul(add(A, B), tmp);
        }
        /// <summary>
        /// metoda dělí matici danným číslem
        /// </summary>
        /// <param name="A">matice k dělení</param>
        /// <param name="val">dělitel</param>
        /// <returns>vrací výslednou matici typu double[,]</returns>
        public double[,] div(double[,] A, double val)
        {
            for (int i = 0; i < A.GetLength(0); i++)
            {
                for (int j = 0; j < A.GetLength(1); j++)
                {
                    tmpMatrix[i, j] = A[i, j] / val;
                }
            }
            return tmpMatrix;
        }
        /// <summary>
        /// Násobení matic. Počet sloupců první matice musí být roven počtu řádků matice druhé. 
        /// </summary>
        /// <param name="A">matice typu double[,]</param>
        /// <param name="B">matice typu double[,]</param>
        /// <returns>vrací výslednou matici typu double[,]</returns>
        public double[,] mul(double[,] A, double[,] B)
        {
            tmpMatrix = new double[A.GetLength(0), B.GetLength(1)];
            if (A.GetLength(1) != B.GetLength(0)) throw new DimensionException("Počet sloupců matice A není roven počtu řádků matice B !! " + A.GetLength(1) + "!=" + B.GetLength(0));
            for (int i = 0; i < A.GetLength(0); i++)
            {
                for (int j = 0; j < B.GetLength(1); j++)
                {
                    for (int k = 0; k < A.GetLength(1); k++)
                    {
                        tmpMatrix[i, j] += A[i, k] * B[k, j];
                    }
                }
            }
            return tmpMatrix;
        }

        /// <summary>
        /// Metoda provede transpozici matice tj. prohodí řádky za sloupce
        /// </summary>
        /// <param name="A"></param>
        /// <returns>vrací výslednou matici typu double[,]</returns>
        public double[,] transpone(double[,] A)
        {
            tmpMatrix = new double[A.GetLength(1), A.GetLength(0)];
            for (int i = 0; i < A.GetLength(0); i++)
            {
                for (int j = 0; j < A.GetLength(1); j++)
                {
                    tmpMatrix[j, i] = A[i, j];
                }
            }
            return tmpMatrix;
        }

        /// <summary>
        /// Metoda pro výpočet 1.normy matice. 
        /// </summary>
        /// <param name="A"></param>
        /// <returns>Maximu ze součtu absolutních hodnot sloupců matice</returns>
        public double _1norm(double[,] A)
        {
            //double[] tmp = new double[A.GetLength(1)];
            double max = -1;
            for (int i = 0; i < A.GetLength(1); i++)
            {
                double tmp = 0;
                for (int j = 0; j < A.GetLength(0); j++)
                {
                    tmp += Math.Abs(A[j, i]);
                }
                max = Math.Max(tmp, max);
            }
            return max;
        }

        public double GetAvg(double[,] matrix)
        {
            double sum = 0;
            int count = 0;
            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                double max = matrix[i, 0];
                for (int j = 1; j < matrix.GetLength(1); j++)
                {
                    if (matrix[i, j] >= max)
                    {
                        max = matrix[i, j];
                    }
                }
                if (max > 0)
                {
                    sum += max;
                    count++;
                }
            }
            return sum / count;
        }

        public double GetMax(double[,] matrix)
        {
            double max = matrix[0, 0];
            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    if (matrix[i, j] >= max)
                    {
                        max = matrix[i, j];
                    }
                }
            }
            return max;
        }

        public double[,] fill(int val, double[,] Z)
        {
            for (int i = 0; i < Z.GetLength(0); i++)
            {
                for (int j = 0; j < Z.GetLength(1); j++)
                {
                    Z[i, j] = val;
                }
            }
            return Z;
        }

        //private double max(double[] A)
        //{
        //    double max = -1;
        //    for (int i = 1; i < A.GetLength(0); i++)
        //    {
        //        max = Math.Max(A[i - 1], A[i]);
        //    }
        //    return max;
        //}
        /// <summary>
        /// vytiskne matici
        /// </summary>
        /// <param name="A"></param>
        public void print(double[,] A)
        {
            for (int i = 0; i < A.GetLength(0); i++)
            {
                for (int j = 0; j < A.GetLength(1); j++)
                {
                    Console.Write("{0} ", Math.Round(A[i, j], 2) * 100);
                    //Console.Write("{0} ", A[i, j]);
                }
                Console.WriteLine();
            }
        }
    }
}
